package com.ikas.ai.server.module.system.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ikas.ai.consts.Consts;
import com.ikas.ai.enums.MenuTypeEnum;
import com.ikas.ai.server.error.BusinessException;
import com.ikas.ai.server.module.system.dao.PermissionDAO;
import com.ikas.ai.server.module.system.dao.RoleDAO;
import com.ikas.ai.server.module.system.model.Permission;
import com.ikas.ai.server.module.system.model.Role;
import com.ikas.ai.server.module.system.model.User;
import com.ikas.ai.server.module.system.model.vo.PermissionVo;
import com.ikas.ai.server.module.system.model.vo.RoleAuthVo;
import com.ikas.ai.utils.RedisUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

@SuppressWarnings("all")
@Service
public class PermissionService extends ServiceImpl<PermissionDAO, Permission> {


    @Autowired
    private UserService userService;
    @Autowired
    private PermissionDAO permissionDAO;
    @Autowired
    private RoleDAO roleDAO;
    @Autowired
    private RedisUtil redisUtil;

    /**
     * 查询菜单列表 排除按钮
     *
     * @return
     */
    public List<Permission> queryNotButtonList() {
        QueryWrapper<Permission> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .ne(Permission::getType, 2)
                .orderByAsc(Permission::getOrderby);
        List<Permission> permissions = permissionDAO.selectList(queryWrapper);
        return permissions;
    }

    /**
     * 分页查询
     *
     * @param name
     * @param type
     * @param level
     * @return
     */
    public List<Permission> pageQueryPermissionList(String name, Integer type, Integer level) {
        LambdaQueryChainWrapper<Permission> lambdaQueryChainWrapper = new LambdaQueryChainWrapper<>(permissionDAO);
        List<Permission> list = lambdaQueryChainWrapper.eq(type != null, Permission::getType, type)
                .eq(level != null, Permission::getMenuLevel, level)
                .like(StringUtils.isNotBlank(name), Permission::getName, name)
                .orderByAsc(Permission::getOrderby)
                .list();
        //处理父节点数据
        Map<Long, Permission> menuMap = new HashMap<>(16);
        for (Permission s : list) {
            menuMap.put(s.getId(), s);
        }
        for (Permission s : list) {
            Permission parent = menuMap.get(s.getPid());
            if (Objects.nonNull(parent)) {
                s.setpName(parent.getName());
            }
        }
        return list;
    }

    /**
     * 删除菜单操作，如果当前菜单存在子菜单,则将子菜单一并删除,以及按钮数据
     * 1，先删除菜单表数据
     * 2，然后再删除角色表与菜单表关联数据
     *
     * @param id
     */
    @Transactional(rollbackFor = BusinessException.class)
    public void deleteById(Long id) {
        Permission permission = permissionDAO.selectById(id);
        Assert.notNull(permission, "菜单不存在");
        List<Long> ids = new ArrayList<>();
        ids.add(id);
        switch (permission.getType()) {
            case 0:
                Map<String, Object> map = new HashMap<>(2);
                LambdaQueryWrapper<Permission> queryWrapper = new QueryWrapper<Permission>().lambda().eq(Permission::getPid, id);
                List<Permission> permissions = permissionDAO.selectList(queryWrapper);
                Set<Long> list = permissions.stream().map(Permission::getId).collect(Collectors.toSet());
                for (Long menuId : list) {
                    //查询按钮信息
                    map.put("pid", menuId);
                    List<Permission> selectByMap = permissionDAO.selectByMap(map);
                    Set<Long> idSet = selectByMap.stream().map(Permission::getId).collect(Collectors.toSet());
                    ids.addAll(idSet);
                }
                ids.addAll(list);
                break;
            case 1:
                LambdaQueryWrapper<Permission> lambdaQueryWrapper = new QueryWrapper<Permission>().lambda().eq(Permission::getPid, id);
                List<Permission> pers = permissionDAO.selectList(lambdaQueryWrapper);
                Set<Long> set = pers.stream().map(Permission::getId).collect(Collectors.toSet());
                ids.addAll(set);
                break;
            case 2:
                break;
        }
        //删除权限菜单信息
        permissionDAO.deleteBatchIds(ids);

        //删除关联角色表信息
        permissionDAO.deleteRolePermByIds(ids);
    }

    /**
     * 根据角色id查询对应的权限列表
     *
     * @param roleId
     * @return
     */
    public List<Permission> getPermissionListByRoleId(Long roleId) {
        List<Permission> permissions = permissionDAO.findPermissionByRole(roleId);
        return permissions.stream().filter(i ->
                i.getPid() != 0 && i.getPid() != null && !Consts.PID.equals(i.getPid())
        ).collect(Collectors.toList());
    }

    /**
     * 给角色授权
     * 1,先查询出角色所关联的用户
     * 2,再redis删除用户和权限之间的关系
     *
     * @param roleAuthVo
     */
    @Transactional(rollbackFor = BusinessException.class)
    public void setAuth(RoleAuthVo roleAuthVo) {
        //先删除现有拥有菜单
        Long roleId = roleAuthVo.getRoleId();
        permissionDAO.deletePermissionByRoleId(roleId);
        //根据子节点查询父节点
        List<Integer> menuIdList = roleAuthVo.getMenuIdList();
        List<Integer> pidList = permissionDAO.selectPid(menuIdList);
        pidList = pidList.stream().filter(Objects::nonNull).filter(i -> i != 0).collect(Collectors.toList());
        menuIdList.addAll(pidList);
        roleAuthVo.setMenuIdList(menuIdList);
        permissionDAO.setAuth(roleAuthVo);
        //更新redis下 角色关联用户的权限信息
        List<User> userList = userService.selectByRoleId(roleId);
        for (User user : userList) {
            String userName = user.getUserName();
            userService.updateRedis(userName);
        }
    }

    /**
     * 保存或更新权限信息
     *
     * @param permission
     */
    @Transactional(rollbackFor = BusinessException.class)
    public void saveOrUpdatePermission(Permission permission) {
        Long id = permission.getId();
        if (Objects.isNull(permission.getPid())) {
            permission.setPid(0L);
        }
        this.saveOrUpdate(permission);
        //更新redis权限信息
        List<Long> roleIds = permissionDAO.selectRoleIdsByPermId(id);
        roleIds.forEach(roleId -> {
            List<User> userList = userService.selectByRoleId(roleId);
            userList.forEach(user -> {
                String userName = user.getUserName();
                userService.updateRedis(userName);
            });
        });
    }


    /**
     * 生成按钮权限操作
     *
     * @param permissionVo
     */
    @Transactional(rollbackFor = BusinessException.class)
    public void generateButton(PermissionVo permissionVo) {
        //父级菜单id
        Long menuId = permissionVo.getMenuId();
        //父级菜单权限标志
        String parentPermission = permissionVo.getParentPermission();
        List<String> permissions = permissionVo.getPermission();
        String permissionTitles = permissionVo.getPermissionTitles();
        //是否新增
        Integer additional = permissionVo.getAdditional();
        if (additional.intValue() == 1) {
            //删除旧的 再新增新的
            Map<String, Object> map = new HashMap<>(2);
            map.put("pid", menuId);
            permissionDAO.deleteByMap(map);
        }
        String[] titles = permissionTitles.split(",");
        //新增按钮
        for (int index = 0; index < permissions.size(); index++) {
            String title = titles[index];
            String flag = permissions.get(index);
            Permission permission = new Permission();
            permission.setName(title);
            permission.setPermissions(parentPermission + ":" + flag);
            permission.setOrderby(index);
            permission.setPid(menuId);
            permission.setType(MenuTypeEnum.BUTTON.getCode());
            permission.setHidden(1);
            permission.setMenuLevel(3);
            permissionDAO.insert(permission);
        }
    }

    /**
     * 获取资源
     *
     * @param permissionVo
     */
    public Set<Permission> getResource(String userName) {
        //1.查询所有资源
        List<Permission> listServiceResult = permissionDAO.getAllResource();
        //超级管理员
        if (Consts.ROOT.equals(userName)) {
            return listTreeNodes(listServiceResult);
        }
        //2.查询用户权限关联的资源
        List<Permission> resourceList = permissionDAO.getResourceByUserName(userName);
        //3.根据权限关联的资源（子级）查询所有父级
        /*List<Permission> parentResourceList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(resourceList)) {
            for (Permission permission : resourceList) {
                getParentResourceList(listServiceResult, permission.getId(), parentResourceList);
            }
        }*/
        //查询到的资源组装成树节点
        Set<Permission> permissions = listTreeNodes(resourceList);
        return new LinkedHashSet<>(permissions);
    }

    /**
     * 获取树结构数据
     *
     * @return
     */
    public Set<Permission> listTreeNodes(List<Permission> allList) {
        List<Permission> parentList = new ArrayList<>();//根节点
        List<Permission> allResourceList = null;
        if (!CollectionUtils.isEmpty(allList)) {
            allResourceList = allList;
            for (Permission resource : allList) {
                if (Objects.isNull(resource.getPid()) || resource.getPid() == 0L) {
                    parentList.add(resource);
                }
            }
        }
        //返回的树形节点数据
        List<Permission> treeNodeList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(parentList)) {
            for (Permission parent : parentList) {
                //递归查询所有子节点
                treeNodeList.add(recursiveTree(parent, allResourceList));
            }
        }
        Set<Permission> set = treeNodeList.stream().collect(Collectors.toSet());
        return set;
    }

    /**
     * 递归算法解析成树形结构
     */
    public Permission recursiveTree(Permission parentNode, List<Permission> allResourceList) {
        List<Permission> childTreeNodes = getChildTree(parentNode.getId(), allResourceList);
        if (!CollectionUtils.isEmpty(childTreeNodes)) {
            for (Permission child : childTreeNodes) {
                Permission n = recursiveTree(child, allResourceList);
                parentNode.getChildrenList().add(n);
            }
        }
        return parentNode;
    }

    /**
     * 根据父节点ID获取所有子节点
     */
    public List<Permission> getChildTree(Long parentId, List<Permission> allResourceList) {
        List<Permission> childNodes = new ArrayList<>();
        if (!CollectionUtils.isEmpty(allResourceList)) {
            for (Permission resource : allResourceList) {
                if (parentId.equals(resource.getPid())) {
                    childNodes.add(resource);
                }
            }
        }
        return childNodes;
    }


    public Set<String> getUserPermissions(User user) {
        List<Permission> resourcesList = new ArrayList<>();
        // admin用户默认拥有所有权限
        if (Consts.ROOT.equalsIgnoreCase(user.getUserName())) {
            QueryWrapper<Permission> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().orderByAsc(Permission::getOrderby);
            resourcesList = permissionDAO.selectList(queryWrapper);
        } else {
            // 查询用户角色
            List<Role> roles = roleDAO.getRoleListById(user.getId());
            Set<Role> roleSet = roles.stream().filter(item -> item != null).collect(Collectors.toSet());
            for (Role role : roleSet) {
                // 根据用户角色查询权限
                resourcesList.addAll(permissionDAO.findPermissionByRole(role.getId()));
            }
        }
        Set<String> permissionSet = new HashSet<>();
        if (!CollectionUtils.isEmpty(resourcesList)) {
            resourcesList.stream().filter(item -> item != null).forEach(resources -> {
                String permission = null;
                if (StringUtils.isNotBlank(permission = resources.getPermissions())) {
                    permissionSet.addAll(Arrays.asList(permission.trim().split(",")));
                }
            });
        }
        return permissionSet;
    }

}
